package com.wangjie.pattern.singleton;

/**
 * 双重检查实现单例模式为何要使用volatile关键字
 * 
 * singleton = new Singleton() 在我们看来就是一句话操作而已, 但在虚拟机看来它一共分为了几个指令操作:
 * 
 * 1.为对象分配内存空间
 * 2.初始化对象
 * 3.将引用指向对象的内存空间地址
 * 
 * 虚拟机执行的时候不一定是按顺序123的顺序执行, 也有可能是132, 这是虚拟机的重排序引起的, 单线程情况下是没有什么bug的, 最终都会创建出对象, 只是先后顺序不同, 但是
 * 在上面例子中会出现这么一种情况:
 * 
 * 假如线程A执行singleton = new Singleton()虚拟机是按132顺序执行, 当执行到3的时候singleton引用已经不为空, 此时若线程B执行到第一次校验处(第一次校验不在同步代
 * 码中, 因此所有线程随时都可以访问), 它判断singleton == null得到false, 直接返回singleton对象, 但是此时singleton对象还没初始化完成, 因此很有可能会发生bug
 */
public class Singleton3 {
    private static volatile Singleton3 singleton;

    private Singleton3() {

    }

    public static Singleton3 getInstance() {
        if (singleton == null) {
            synchronized (Singleton3.class) {
                if (singleton == null) {
                    singleton = new Singleton3();
                }
            }
        }

        return singleton;
    }
}